package org.ala.tcp_feign_client.spring.feign.selector;

import java.util.List;

import org.ala.tcp_feign_client.ITcpFeignClient;
import org.ala.tcp_feign_client.context.TcpFeignClientContext;
import org.ala.tcp_feign_common.logs.LoggerFactory;
import org.slf4j.Logger;

/**
 * 默认的选择器-轮训
 * <p>	不要求严格意义上的线程安全轮训
 *
 * @author 骆毅(ala)
 * @date 2024年4月22日
 */
public class DefaultTcpFeignClientSelector implements ITcpFeignClientSelector {
	
	
	static Logger log = LoggerFactory.getLogger("tcp-feign", "client");

	
	/**
	 * 当前选择索引
	 */
	protected int idx = 0;
	
	@Override
	public ITcpFeignClient select(List<ITcpFeignClient> clients) {
		if (clients == null || clients.isEmpty()) {return null;}
		
		int times = clients.size();
		//	可局部保证线程安全
		int i = idx++;
		while (times-- > 0) {
			//	随机下标选择
			int _i = i++ % clients.size();
			if (i > clients.size()) {i = 0;}
			ITcpFeignClient client = clients.get(_i);
			if (client == null) {continue;}
			
			if (tryConnect(client, _i, clients)) {return client;}
		}
		//	如果找了一轮还没找到，说明当前没有可用链接
		return null;
	}
	/**
	 * 检测client是否可用
	 * <p>	如果不在，则重新连接。此时如果连接失败，添加进队列
	 * <p>	如果在，直接返回null
	 */
	protected boolean tryConnect(ITcpFeignClient client, int i, List<ITcpFeignClient> clients) {
		//	如果当前已经是登录成功状态，直接返回可用
		if (client.isLogin() == 1) {return true;}
		
		//	如果当前链接成功，说明还在等登录消息
		if (client.isActive()) {
			if (waitForLogin(client, 5)) {return true;}
			else {return false;}
		}
		
		// 如果连接也没有，判断client是否在重连队列中
		//	如果在重连队列中，不管（重连成功后client会被重新写入clients，但他这次是怎么被选择到的。。。）
		if (TcpFeignClientContext.instance().getReconnectScheduled().contains(client)) {
			log.info("[DefaultTcpFeignClientSelector client] 该client当前链接不成功，但已经在重连队列中 host:" + client.host() + " port:" + client.port() + " suffix:" + client.suffix() + " username:" + client.username() + " password:" + client.password());
			return false;
		}
		//	如果不在重连队列中，先尝试连接，链接失败时，放入重连队列
		else {
			//	尝试重连，若重连成功，等待登录成功
			try {
				client.connect();
				if (waitForLogin(client, 5)) {return true;}
				else {return false;}
			} catch (Exception e) {
				//	连失败，放入等待重连队列中
				log.info("[DefaultTcpFeignClientSelector client] 该client当前链接不成功，放入重连队列中 host:" + client.host() + " port:" + client.port() + " suffix:" + client.suffix() + " username:" + client.username() + " password:" + client.password(), e);
				return false;
			}
		}
	}
	/**
	 * 等登录成功消息
	 */
	protected boolean waitForLogin(ITcpFeignClient client, int times) {
		int isLogin = -2;
		while (times-- > 0) {
			isLogin = client.isLogin();
			if (isLogin == 1) {return true;}
			else if (isLogin < 0) {
				log.warn("[DefaultTcpFeignClientSelector connect] client端登录失败，来个人管管. host:" + client.host() + " port:" + client.port() + " suffix:" + client.suffix() + " username:" + client.username() + " password:" + client.password());
				return false;
			}
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				log.warn("[DefaultTcpFeignClientSelector connect] client等待登录成功线程被异常中断 ", e);
				return false;
			}
		}
		log.warn("[DefaultTcpFeignClientSelector connect] client端登录超时，来个人管管. host:" + client.host() + " port:" + client.port() + " suffix:" + client.suffix() + " username:" + client.username() + " password:" + client.password());
		return false;
	}

}
